// PositionDlg.cpp : implementation file
//

#include "stdafx.h"
#include "LightspeedTraderAPIDemo.h"
#include "PositionDlg.h"
//#include "afxdialogex.h"

#include "OrderDlg.h"
#include "ExecutionDlg.h"

enum STATIC_VALUE {
	SYMBOL,
	BP_TYPE,

	END_OF_STATIC_VALUES
};

enum POSITION_CHANGE_VALUES { //values to be updated on PositionChange messages
	OPEN_PL = END_OF_STATIC_VALUES,
	OPEN_PL_AVE,
	MARKED_PL,

	END_OF_POSITION_CHANGE_VALUES
};

enum ORDER_CHANGE_VALUES {  //values to be updated on OrderChange messages
	SHARES = END_OF_POSITION_CHANGE_VALUES,
	TOTAL_PRICE,
	TOTAL_PRICE_AVE,
	CLOSED_PL,
	CLOSED_PL_AVE,
	CB_TRADITIONAL,
	CB_AVE,
	MONEY_INVESTED,
	VALUE,
	LONG_VALUE,
	SHORT_VALUE,
	DOLLAR_VALUE,
	LONG_DOLLAR_VALUE,
	SHORT_DOLLAR_VALUE,
	MARGIN_REQUIREMENT,
	MARGIN_FACTOR,
	PL_LAST_PRICE,
	PENDING_ORDER_COUNT,
	PENDING_BUY_ORDER_COUNT,
	PENDING_SELL_ORDER_COUNT,
	SHARES_TRADED,
	NUM_TRADES,
	ADDED_LIQUIDITY,
	ADDED_LIQUIDITY_EXECUTIONS,
	REMOVED_LIQUIDITY,
	REMOVED_LIQUIDITY_EXECUTIONS,
	SHORT_POSITION_LIMIT,

	END_OF_ORDER_CHANGE_VALUES
};

// PositionDlg dialog

IMPLEMENT_DYNAMIC(PositionDlg, CModelessDialog)

PositionDlg::PositionDlg(CWnd* pParent /*=NULL*/)
	: CModelessDialog(PositionDlg::IDD, pParent)
	, m_PosDataListCtrl(CListCtrl())
	, m_PosCombo(CComboBox())
	, account(NULL)
	, position(NULL)
	, m_PosDispType(ALL_POS)
{
	SetAPIFunctions();
}

PositionDlg::~PositionDlg()
{
	if (account)
	{
		account->L_Detach(this);
		account = NULL;
	}

	position = NULL;
}

BOOL PositionDlg::Create(CWnd *pParentWnd /*= CWnd::FromHandle(L_GetMainWnd())*/)
{
	return __super::Create(PositionDlg::IDD, pParentWnd);
}

void PositionDlg::DoDataExchange(CDataExchange* pDX)
{
	__super::DoDataExchange(pDX);

	DDX_Control(pDX, IDC_POSCOMBO, m_PosCombo);
	DDX_Control(pDX, IDC_POSDATALIST, m_PosDataListCtrl);
	DDX_Radio(pDX, IDC_ALLRADIO, m_PosDispType);
}

BOOL PositionDlg::OnInitDialog()
{
	__super::OnInitDialog();

	DWORD style = m_PosDataListCtrl.GetExtendedStyle();
	style |= LVS_EX_FULLROWSELECT;
	style |= LVS_EX_GRIDLINES;
	style |= LVS_EX_DOUBLEBUFFER;
	m_PosDataListCtrl.SetExtendedStyle(style);

	m_PosDataListCtrl.InsertColumn(0,"API Function", LVCFMT_LEFT, 130, 0);
	m_PosDataListCtrl.InsertColumn(1,"Value", LVCFMT_LEFT, 130, 1);

	InitializeDataCtrlRows();

	account = L_GetAccount();
	account->L_Attach(this);

	UpdatePosCombo();

	return TRUE;
}

void PositionDlg::InitializeDataCtrlRows()
{
	for (int i = 0; i < END_OF_ORDER_CHANGE_VALUES; ++i)
	{
		m_PosDataListCtrl.InsertItem(i,APIFunctions[i]);
	}
}

void PositionDlg::UpdateStaticPositionData()
{
	m_PosDataListCtrl.SetRedraw(FALSE); //disable redraw to reduce control flickering
	for (int i = 0; i < END_OF_STATIC_VALUES; ++i)
	{
		m_PosDataListCtrl.SetItemText(i, 1, GetTextForFunction(i));
	}
	m_PosDataListCtrl.SetRedraw(TRUE);
}

void PositionDlg::UpdatePositionChangePositionData()
{
	m_PosDataListCtrl.SetRedraw(FALSE); //disable redraw to reduce control flickering
	for (int i = END_OF_STATIC_VALUES; i < END_OF_POSITION_CHANGE_VALUES; ++i)
	{
		m_PosDataListCtrl.SetItemText(i, 1, GetTextForFunction(i));
	}
	m_PosDataListCtrl.SetRedraw(TRUE);
}

void PositionDlg::UpdateOrderChangePositionData()
{
	m_PosDataListCtrl.SetRedraw(FALSE); //disable redraw to reduce control flickering
	for (int i = END_OF_POSITION_CHANGE_VALUES; i < END_OF_ORDER_CHANGE_VALUES; ++i)
	{
		m_PosDataListCtrl.SetItemText(i, 1, GetTextForFunction(i));
	}
	m_PosDataListCtrl.SetRedraw(TRUE);
}

void PositionDlg::UpdatePosCombo()
{
	if (!account)
	{
		return;
	}

	switch(m_PosDispType)
	{
	case ALL_POS:
		UpdateComboBox(m_PosCombo, account->positions_begin(), account->positions_end());
		break;
	case OPEN_POS:
		UpdateComboBox(m_PosCombo, account->open_positions_begin(), account->open_positions_end());
		break;
	case LONG_POS:
		UpdateComboBox(m_PosCombo, account->long_positions_begin(), account->long_positions_end());
		break;
	case SHORT_POS:
		UpdateComboBox(m_PosCombo, account->short_positions_begin(), account->short_positions_end());
		break;
	}
	
}

void PositionDlg::UpdateComboBox(CComboBox &cBox, position_iterator itStart, position_iterator itEnd)
{
	if (! cBox.m_hWnd)
	{
		return;
	}

	bool curSelSaved = false;
	CString curSel;
	if (cBox.GetCount() > 0)
	{
		if (cBox.GetCurSel() != CB_ERR)
		{
			cBox.GetLBText(cBox.GetCurSel(), curSel);
			curSelSaved = true;
		}

		while (cBox.GetCount() > 0)
		{
			cBox.DeleteString(0);
		}
	}

	for (position_iterator it(itStart); it != itEnd; ++it)
	{
		cBox.AddString((*it)->L_Symbol());
	}

	if (curSelSaved)
	{
		CString text;
		int idx;
		bool found = false;
		for (idx = 0; idx < cBox.GetCount(); ++idx)
		{
			cBox.GetLBText(idx,text);
			if (text == curSel)
			{
				found = true;
				break;
			}
		}

		if (found)
		{
			cBox.SetCurSel(idx);
		}
	}
}

void PositionDlg::FindPosition(CComboBox &cBox)
{
	CString sym;
	cBox.GetLBText(cBox.GetCurSel(), sym);

	position = account->L_FindPosition(sym.GetBuffer());

	UpdateStaticPositionData();
	UpdatePositionChangePositionData();
	UpdateOrderChangePositionData();
}

void PositionDlg::SetAPIFunctions()
{
	//clear APIFunction array
	memset(APIFunctions,NULL,sizeof(APIFunctions));

	strcpy_s(APIFunctions[SYMBOL], "Symbol");
	strcpy_s(APIFunctions[BP_TYPE], "BP Type");
	strcpy_s(APIFunctions[SHARES], "Shares");
	strcpy_s(APIFunctions[TOTAL_PRICE], "Total Price");
	strcpy_s(APIFunctions[TOTAL_PRICE_AVE], "Total Price by Ave");
	strcpy_s(APIFunctions[CLOSED_PL], "Closed PL");
	strcpy_s(APIFunctions[CLOSED_PL_AVE], "Closed PL by Ave");
	strcpy_s(APIFunctions[OPEN_PL], "Open PL");
	strcpy_s(APIFunctions[OPEN_PL_AVE], "Open PL by Ave");
	strcpy_s(APIFunctions[MARKED_PL], "Marked PL");
	strcpy_s(APIFunctions[CB_TRADITIONAL], "CB Traditional");
	strcpy_s(APIFunctions[CB_AVE], "CB by Ave");
	strcpy_s(APIFunctions[MONEY_INVESTED], "Money Invested");
	strcpy_s(APIFunctions[VALUE], "Value");
	strcpy_s(APIFunctions[LONG_VALUE], "Long Value");
	strcpy_s(APIFunctions[SHORT_VALUE], "Short Value");
	strcpy_s(APIFunctions[DOLLAR_VALUE], "Dollar Value");
	strcpy_s(APIFunctions[LONG_DOLLAR_VALUE], "Long Dollar Value");
	strcpy_s(APIFunctions[SHORT_DOLLAR_VALUE], "Short Dollar Value");
	strcpy_s(APIFunctions[MARGIN_REQUIREMENT], "Margin Requirement");
	strcpy_s(APIFunctions[MARGIN_FACTOR], "Margin Factor");
	strcpy_s(APIFunctions[PL_LAST_PRICE], "PL Last Price");
	strcpy_s(APIFunctions[PENDING_ORDER_COUNT], "Pending Order Count");
	strcpy_s(APIFunctions[PENDING_BUY_ORDER_COUNT], "Pending Buy Order Count");
	strcpy_s(APIFunctions[PENDING_SELL_ORDER_COUNT], "Pending Sell Order Count");
	strcpy_s(APIFunctions[SHARES_TRADED], "Shares Traded");
	strcpy_s(APIFunctions[NUM_TRADES], "Num Trades");
	strcpy_s(APIFunctions[ADDED_LIQUIDITY], "Added Liquidity");
	strcpy_s(APIFunctions[ADDED_LIQUIDITY_EXECUTIONS], "Added Liquidity Executions");
	strcpy_s(APIFunctions[REMOVED_LIQUIDITY], "Removed Liquidity");
	strcpy_s(APIFunctions[REMOVED_LIQUIDITY_EXECUTIONS], "Removed Liquidity Executions");
	strcpy_s(APIFunctions[SHORT_POSITION_LIMIT], "Short Position Limit");
}

//will map index enums to the equivilant API functions
CString PositionDlg::GetTextForFunction(int function)
{
	CString retString = "";
	switch (function)
	{
	case SYMBOL:
		{
			retString = position->L_Symbol();
		}
		break;
	case BP_TYPE:
		{
			switch (position->L_BPType())
			{
			case L_BPType::ALL:
				retString = "ALL";
				break;
			case L_BPType::EQUITIESOPTIONS:
				retString = "EQUITIESOPTIONS";
				break;
			case L_BPType::FUTURES:
				retString = "FUTURES";
				break;
			case L_BPType::OPTIONS:
				retString = "OPTIONS";
				break;
			}
		}
		break;
	case SHARES:
		{
			retString.Format("%d", position->L_Shares());
		}
		break;
	case TOTAL_PRICE:
		{
			retString.Format("%.2f", position->L_TotalPrice());
		}
		break;
	case TOTAL_PRICE_AVE:
		{
			retString.Format("%.2f", position->L_TotalPriceByAve());
		}
		break;
	case CLOSED_PL:
		{
			retString.Format("%.2f", position->L_ClosedPL());
		}
		break;
	case CLOSED_PL_AVE:
		{
			retString.Format("%.2f", position->L_ClosedPLByAve());
		}
		break;
	case OPEN_PL:
		{
			retString.Format("%.2f", position->L_OpenPL());
		}
		break;
	case OPEN_PL_AVE:
		{
			retString.Format("%.2f", position->L_OpenPLByAve());
		}
		break;
	case MARKED_PL:
		{
			retString.Format("%.2f", position->L_MarkedPL());
		}
		break;
	case CB_TRADITIONAL:
		{
			retString.Format("%.2f", position->L_CostBasisTraditional());
		}
		break;
	case CB_AVE:
		{
			retString.Format("%.2f", position->L_CostBasisByAve());
		}
		break;
	case MONEY_INVESTED:
		{
			retString.Format("%.2f", position->L_MoneyInvested());
		}
		break;
	case VALUE:
		{
			retString.Format("%.2f", position->L_Value());
		}
		break;
	case LONG_VALUE:
		{
			retString.Format("%.2f", position->L_LongValue());
		}
		break;
	case SHORT_VALUE:
		{
			retString.Format("%.2f", position->L_ShortValue());
		}
		break;
	case DOLLAR_VALUE:
		{
			retString.Format("%.2f", position->L_DollarValue());
		}
		break;
	case LONG_DOLLAR_VALUE:
		{
			retString.Format("%.2f", position->L_LongDollarValue());
		}
		break;
	case SHORT_DOLLAR_VALUE:
		{
			retString.Format("%.2f", position->L_ShortDollarValue());
		}
		break;
	case MARGIN_REQUIREMENT:
		{
			retString.Format("%.2f", position->L_MarginRequirement());
		}
		break;
	case MARGIN_FACTOR:
		{
			retString.Format("%.2f", position->L_MarginFactor());
		}
		break;
	case PL_LAST_PRICE:
		{
			retString.Format("%.2f", position->L_PLLastPrice());
		}
		break;
	case PENDING_ORDER_COUNT:
		{
			retString.Format("%d", position->L_PendingOrdersCount());
		}
		break;
	case PENDING_BUY_ORDER_COUNT:
		{
			retString.Format("%d", position->L_PendingBuyOrdersCount());
		}
		break;
	case PENDING_SELL_ORDER_COUNT:
		{
			retString.Format("%d", position->L_PendingSellOrdersCount());
		}
		break;
	case SHARES_TRADED:
		{
			retString.Format("%d", position->L_SharesTraded());
		}
		break;
	case NUM_TRADES:
		{
			retString.Format("%d", position->L_NumTrades());
		}
		break;
	case ADDED_LIQUIDITY:
		{
			retString.Format("%d", position->L_AddedLiquidity());
		}
		break;
	case ADDED_LIQUIDITY_EXECUTIONS:
		{
			retString.Format("%d", position->L_AddedLiquidityExecutions());
		}
		break;
	case REMOVED_LIQUIDITY:
		{
			retString.Format("%d", position->L_RemovedLiquidity());
		}
		break;
	case REMOVED_LIQUIDITY_EXECUTIONS:
		{
			retString.Format("%d", position->L_RemovedLiquidityExecutions());
		}
		break;
	case SHORT_POSITION_LIMIT:
		{
			retString.Format("%d", account->L_GetShortPositionLimit(position->L_Symbol()));
		}
		break;
	}
	return retString;
}

//L_Oberver
void PositionDlg::HandleMessage(L_Message const *pMsg)
{
	switch (pMsg->L_Type())
	{
	case L_MsgShortLimitChange::id:
	case L_MsgPositionChange::id:
		if (position && !strcmp(pMsg->L_Symbol(),position->L_Symbol()))
		{
			UpdatePositionChangePositionData();
		}
		break;
	case L_MsgOrderChange::id:
		{
			if (position && !strcmp(pMsg->L_Symbol(), position->L_Symbol()))
			{
				UpdateOrderChangePositionData();
			}
			UpdatePosCombo();
		}
		break;
	}
}

BEGIN_MESSAGE_MAP(PositionDlg, CModelessDialog)
	ON_WM_SIZE()
	ON_CBN_SELCHANGE(IDC_POSCOMBO, OnCbnSelchangePosCombo)
	ON_BN_CLICKED(IDC_ALLRADIO, OnBnClickedAllRadio)
	ON_BN_CLICKED(IDC_OPENRADIO, OnBnClickedOpenRadio)
	ON_BN_CLICKED(IDC_LONGRADIO, OnBnClickedLongRadio)
	ON_BN_CLICKED(IDC_SHORTRADIO, OnBnClickedShortRadio)
	ON_COMMAND(ID_VIEW_ORDERS, OnViewOrders)
	ON_COMMAND(ID_VIEW_EXECUTIONS, OnViewExecutions)
END_MESSAGE_MAP()

// PositionDlg message handlers

void PositionDlg::OnSize(UINT nType, int cx, int cy)
{
	__super::OnSize(nType, cx, cy);

	ResizeControls();
}

void PositionDlg::ResizeControls()
{
	if (m_hWnd && m_PosDataListCtrl.m_hWnd)
	{
		RECT Rect;
		GetClientRect(&Rect);

		RECT ctrlRect;
		m_PosDataListCtrl.GetWindowRect(&ctrlRect);
		ScreenToClient(&ctrlRect);

		Rect.top = ctrlRect.top;

		m_PosDataListCtrl.MoveWindow(&Rect);
	}
}

void PositionDlg::OnCbnSelchangePosCombo()
{
	FindPosition(m_PosCombo);
}

void PositionDlg::OnShowOrders()
{
	if (position)
	{
		OrderDlg *pDlg = new OrderDlg(position);
	
		if (! CLightspeedTraderAPIDemoApp::GetInstance()->CreateDlg(pDlg))
		{
			delete pDlg;
		}
	}
}

void PositionDlg::OnShowExecutions()
{
	if (position)
	{
		ExecutionDlg *pDlg = new ExecutionDlg(position);

		if (! CLightspeedTraderAPIDemoApp::GetInstance()->CreateDlg(pDlg))
		{
			delete pDlg;
		}
	}
}

void PositionDlg::OnBnClickedAllRadio()
{
	if (m_PosDispType != ALL_POS)
	{
		m_PosDispType = ALL_POS;
		UpdatePosCombo();
	}
}

void PositionDlg::OnBnClickedOpenRadio()
{
	if (m_PosDispType != OPEN_POS)
	{
		m_PosDispType = OPEN_POS;
		UpdatePosCombo();
	}
}

void PositionDlg::OnBnClickedLongRadio()
{
	if (m_PosDispType != LONG_POS)
	{
		m_PosDispType = LONG_POS;
		UpdatePosCombo();
	}
}

void PositionDlg::OnBnClickedShortRadio()
{
	if (m_PosDispType != SHORT_POS)
	{
		m_PosDispType = SHORT_POS;
		UpdatePosCombo();
	}
}

void PositionDlg::OnViewOrders()
{
	OnShowOrders();
}

void PositionDlg::OnViewExecutions()
{
	OnShowExecutions();
}